/*!
 Temelia - Graph backend samples.

 Copyright (C) 2010 Ceata (http://ceata.org/proiecte/temelia).

 @author Dascalu Laurentiu

 This program is free software; you can redistribute it and
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 3
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "include/samples.h"
#include <temelia/graph.h>
#include <temelia/edge.h>
#include <temelia/graph_matrix.h>
#include <temelia/graph_sparse_matrix.h>
#include <temelia/graph_list.h>

#define SIZE  5
vertex_t vertices[SIZE];
static edge_t edge[SIZE][SIZE];

static void my_edge_delete(edge_t edge)
{
	free(edge_get_label(edge));
	edge_delete(edge);
}

static void iterate(vertex_t src, vertex_t dest, double cost, char *label,
		void *key, int x)
{
	PRINT("Edge [%lu %lu] cost %lf, label %s, key %ld, x %d\n",
			vertex_get_identifier(src), vertex_get_identifier(dest), cost,
			label, (long) key, x);
}

static void init_dummy_graph()
{
	unsigned long i, j;
	char buffer[128];

	for (i = 0; i < SIZE; i++)
	{
		sprintf(buffer, "vertex[%lu]", i);
		vertices[i] = vertex_new(my_strdup(buffer), i, (void *) i);
	}

	for (i = 0; i < SIZE; i++)
		for (j = 0; j < SIZE; j++)
		{
			sprintf(buffer, "label[%lu, %lu]", i, j);
			edge[i][j] = edge_new(vertices[i], vertices[j], i * j, my_strdup(
					buffer), (void *) (j + i * SIZE));
		}
}

static void destroy_dummy_graph()
{
	unsigned long i, j;

	for (i = 0; i < SIZE; i++)
	{
		free(vertex_get_label(vertices[i]));
		vertex_delete(vertices[i]);
	}

	for (i = 0; i < SIZE; i++)
		for (j = 0; j < SIZE; j++)
		{
			free(edge_get_label(edge[i][j]));
			edge_delete(edge[i][j]);
		}
}

#define GENERATE_TEST(type)\
static void sample1_ ## type()\
{\
	int size = 5;\
	void *graph_impl = type ## _new(size);\
\
	PRINT("\n\n Sample 1 started \n\n");\
\
	size *= 2;\
	type ## _resize(graph_impl, size);\
\
	type ## _delete(graph_impl);\
\
	PRINT("\n\n Sample 1 ended \n\n");\
}\
\
static void *dummy_init_ ## type()\
{\
	void *graph = type ## _new(SIZE);\
	unsigned long i, j;\
\
	for (i = 0; i < SIZE; i++)\
		for (j = 0; j < SIZE; j++)\
			type ## _add_edge(graph, i, j, edge[i][j]);\
\
	return graph;\
}\
\
static void dummy_destroy_ ## type(void *graph)\
{\
	type ## _delete(graph);\
}\
\
static void sample2_ ## type()\
{\
	int size = 5;\
	unsigned long i, j;\
\
	void *graph = dummy_init_ ## type();\
	edge_t edge;\
\
	PRINT("\n\n Sample 2 started \n\n");\
\
	type ## _iterate(graph, iterate);\
\
	for (i = 0; i < size; i++)\
		for (j = 0; j < size; j++)\
		{\
			edge = type ## _get_edge(graph, i, j);\
			if (edge != type ## _remove_edge(graph, i, j))\
				PRINT("* [File %s] EROARE pe linia %d\n", __FILE__, __LINE__);\
			if (type ## _remove_edge(graph, i, j) != NULL)\
				PRINT("** [File %s] EROARE pe linia %d\n", __FILE__, __LINE__);\
		}\
	dummy_destroy_ ## type(graph);\
\
	PRINT("\n\n Sample 2 ended \n\n");\
}\
\
static void sample3_ ## type()\
{\
	void *graph = dummy_init_ ## type();\
	vertex_t vertex;\
	void *context;\
	unsigned long i, j;\
\
	PRINT("\n\n Sample 3 started \n\n");\
\
	for (i = 0; i < SIZE; i++)\
	{\
		for (j = i; j < SIZE; j++)\
		{\
			type ## _remove_edge(graph, i, j);\
			type ## _remove_edge(graph, i, j);\
		}\
	}\
\
	for (i = 0; i < SIZE; i++)\
	{\
		PRINT("\n\n[nod %lu] Incep afisarea vecinilor\n", i);\
\
		vertex = type ## _first_vertex(graph, i, &context);\
		PRINT("[nod %lu] primul vecin este %lu\n", i, vertex_get_identifier(vertex));\
\
		while ((vertex = type ## _next_vertex(graph, i, &context)))\
			PRINT("[nod %lu] urmatorul vecin este %lu\n", i, vertex_get_identifier(vertex));\
		vertex_debug(vertex, NULL);\
		PRINT("[nod %lu] am terminat de afisat vecinii\n", i);\
	}\
\
	dummy_destroy_ ## type(graph);\
	PRINT("\n\n Sample 3 ended \n\n");\
}\
\
static void sample4_ ## type()\
{\
	unsigned long i, j;\
	void *graph = dummy_init_ ## type();\
\
	PRINT("\n\n Sample 4 started \n\n");\
\
	for (i = 0; i < SIZE; i++)\
	{\
		for (j = i; j < SIZE; j++)\
			type ## _remove_edge(graph, i, j);\
	}\
\
	PRINT("Before transposing\n");\
	type ## _iterate_edges(graph, edge_debug, NULL);\
\
	PRINT("\nAfter transposing\n");\
	type ## _transpose(graph);\
	type ## _iterate_edges(graph, edge_debug, NULL);\
\
	PRINT("Graph dimension: %lu\n", type ## _dimension(graph));\
\
	for (i = 0; i < SIZE; i++)\
	{\
		PRINT("Degree(%lu) = %lu, ", i, type ## _vertex_degree(graph, i));\
		PRINT("In degree(%lu) = %lu, ", i, type ## _vertex_in_degree(graph, i));\
		PRINT("Out degree(%lu) = %lu\n", i, type ## _vertex_out_degree(graph, i));\
	}\
\
	dummy_destroy_ ## type(graph);\
\
	PRINT("\n\n Sample 4 ended \n\n");\
}\
\
static void sample5_ ## type()\
{\
	unsigned long i;\
	void *graph;\
\
	init_dummy_graph();\
	PRINT("\n\n Sample 5 started \n\n");\
\
	graph = dummy_init_ ## type();\
\
	for (i = 0; i < SIZE; i++)\
		type ## _delete_vertex_edges(graph, i, my_edge_delete);\
\
	for (i = 0; i < SIZE; i++)\
	{\
		free(vertex_get_label(vertices[i]));\
		vertex_delete(vertices[i]);\
	}\
\
	dummy_destroy_ ## type(graph);\
	PRINT("\n\n Sample 5 ended \n\n");\
}\

GENERATE_TEST(graph_matrix)

void run_graph_matrix_samples()
{
	//INIT(stdout);
	init_dummy_graph();
	sample1_graph_matrix();
	sample2_graph_matrix();
	sample3_graph_matrix();
	sample4_graph_matrix();
	destroy_dummy_graph();

	sample5_graph_matrix();
	//DESTROY();
}

GENERATE_TEST(graph_sparse_matrix)

void run_graph_sparse_matrix_samples()
{
	//INIT(stdout);
	init_dummy_graph();
	sample1_graph_sparse_matrix();
	sample2_graph_sparse_matrix();
	sample3_graph_sparse_matrix();
	sample4_graph_sparse_matrix();
	destroy_dummy_graph();

	sample5_graph_sparse_matrix();
	//DESTROY();
}

GENERATE_TEST(graph_list)

void run_graph_list_samples()
{
	//INIT(stdout);
	init_dummy_graph();
	sample1_graph_list();
	sample2_graph_list();
	sample3_graph_list();
	sample4_graph_list();
	destroy_dummy_graph();

	sample5_graph_list();
	//DESTROY();
}
